home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / curses.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  10KB  |  459 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. #pragma comment(exestr, "@(#) curses.c 12.1 95/05/09 ")
  6.  
  7. /* RCS $Header: curses.c,v 1.2 88/07/17 15:26:31 shebs Exp $ */
  8.  
  9. /* Interface implementations for the curses version of xconq. */
  10.  
  11. /* This file is rather simple, since there is no support for multiple */
  12. /* displays, no flashy graphics, and very little optimization. */
  13.  
  14. #include "config.h"
  15. #include "misc.h"
  16. #include "period.h"
  17. #include "side.h"
  18. #include "map.h"
  19. #undef bool          /* ugh */
  20. #include <curses.h>
  21.  
  22. #ifdef UNIX
  23. #include <signal.h>   /* needed for ^C handling */
  24. #endif /* UNIX */
  25.  
  26. #define INFOLINES 4
  27.  
  28. int helpwinlines = 1;
  29.  
  30. /* Positions and sizes of the windows. */
  31.  
  32. int wx[20], wy[20], ww[20], wh[20];
  33. int nextwin = 0;                /* number of next window to open */
  34.  
  35. bool alreadyopen = FALSE;       /* flag to prevent double opening */
  36.  
  37. /* Put in a default player, probably the invoker of the program. */
  38. /* Nonempty host name not actually used, but needed to keep things */
  39. /* straight. */
  40.  
  41. add_default_player()
  42. {
  43.     add_player(TRUE, "curses");
  44. }
  45.  
  46. /* Decide what to do about ^C interrupts. */
  47.  
  48. #ifdef UNIX
  49.  
  50. stop_handler()
  51. {
  52.     if (numhumans == 0 || Debug) {
  53.     close_displays();
  54.     exit(1);
  55.     }
  56. }
  57.  
  58. #endif /* UNIX */
  59.  
  60. init_sighandlers()
  61. {
  62. #ifdef UNIX
  63.     signal(SIGINT, stop_handler);
  64. #endif /* UNIX */
  65. }
  66.  
  67. /* "Opening" a curses "display" just involves a standard sequence of calls. */
  68. /* Unfortunately, the "standard sequence" varies from system to system... */
  69.  
  70. open_display(side)
  71. Side *side;
  72. {
  73.     if (!alreadyopen) {
  74.     initscr();
  75.     nonl();
  76.     noecho();
  77. #ifdef USECBREAK
  78.     cbreak();
  79. #endif /* USECBREAK */
  80. #ifdef USECRMODE
  81.     crmode();
  82. #endif /* USECRMODE */
  83.     clear();
  84.     side->display = 1L;
  85.     alreadyopen = TRUE;
  86.     return TRUE;
  87.     } else {
  88.     /* if we got here, we're in big trouble, so clean up quickly */
  89.     clear();
  90.     refresh();
  91.     endwin();
  92.         printf("Can't open a second display!\n");
  93.     return FALSE;
  94.     }
  95. }
  96.  
  97. /* A predicate that tests whether our display can safely be written to. */
  98. /* This is permitted to do side-effects, although curses doesn't need */
  99. /* anything special. */
  100.  
  101. active_display(side)
  102. Side *side;
  103. {
  104.     return (side != NULL && side->host && !side->lost && side->display);
  105. }
  106.  
  107. /* Display will use every character position we can get our hands on. */
  108.  
  109. display_width(side) Side *side; {  return COLS;  }
  110.  
  111. display_height(side) Side *side; {  return LINES;  }
  112.  
  113. /* Displaying the world map usually requires a large bitmap display. */
  114.  
  115. world_display(side) Side *side; {  return FALSE;  }
  116.  
  117. /* Most sizes of things are 1 (i.e. one character cell). */
  118.  
  119. init_misc(side)
  120. Side *side;
  121. {
  122.     side->fw = side->fh = side->hh = side->hch = side->uw = side->uh = 1;
  123.     side->hw = 2;
  124.     side->bd = side->margin = 0;
  125. }
  126.  
  127. /* The "root window" covers our entire display.  In theory, the size of the */
  128. /* screen could exceed what xconq needs, but this is wildly improbable. */
  129.  
  130. create_main_window(side)
  131. Side *side;
  132. {
  133.     create_window(side, 0, 0, COLS, LINES);
  134. }
  135.  
  136. /* Subwindow creator. */
  137.  
  138. create_window(side, x, y, w, h)
  139. Side *side;
  140. int x, y, w, h;
  141. {
  142.     if (x + w > COLS) w = COLS - x;
  143.     if (y + h > LINES) h = LINES - y;
  144.     wx[nextwin] = x;  wy[nextwin] = y;
  145.     ww[nextwin] = w;  wh[nextwin] = h;
  146.     return (nextwin++);
  147. }
  148.  
  149. /* Help window has to be larger than most terminals allow, so blow it off. */
  150.  
  151. create_help_window(side) Side *side; {}
  152.  
  153. /* No special fixups to do. */
  154.  
  155. fixup_windows(side) Side *side; {}
  156.  
  157. enable_input(side) Side *side; {}
  158.  
  159. reset_misc(side) Side *side; {}
  160.  
  161. /* Moving a window just involves plugging in new values. */
  162.  
  163. change_window(side, win, x, y, w, h)
  164. Side *side;
  165. int win, x, y, w, h;
  166. {
  167.     if (x + w > COLS) w = COLS - x;
  168.     if (y + h > LINES) h = LINES - y;
  169.     if (x >= 0) {
  170.     wx[win] = x;  wy[win] = y;
  171.     }
  172.     if (w >= 0) {
  173.     ww[win] = w;  wh[win] = h;
  174.     }
  175. }
  176.  
  177. /* Actually, terminals are really "one-color", but don't take a chance on */
  178. /* confusing the main program. */
  179.  
  180. display_colors(side) Side *side; {  return 2;  }
  181.  
  182. white_color(side) Side *side; {  return 1;  }
  183.  
  184. black_color(side) Side *side; {  return 0;  }
  185.  
  186. /* Can't actually honor any color requests... */
  187.  
  188. request_color(side, name) Side *side; char *name; {  return 0;  }
  189.  
  190. /* Only kind of input is keystrokes, and from only one "display" at that. */
  191.  
  192. get_input()
  193. {
  194.     char ch;
  195.     extern Side *curside;
  196.  
  197.     if (active_display(curside)) {
  198.     draw_cursor(curside);
  199.     ch = getch() & 0177;
  200.     curside->reqtype = KEYBOARD;
  201.     curside->reqch = ch;
  202.     return TRUE;
  203.     }
  204. }
  205.  
  206. /* Wait for any input, don't care what it is. */
  207.  
  208. freeze_wait(side)
  209. Side *side;
  210. {
  211.     refresh();
  212.     getch();
  213. }
  214.  
  215. /* Actually would be nice to do something reasonable here. */
  216.  
  217. flush_input(side) Side *side;  {}
  218.  
  219. /* Trivial abstraction - sometimes other routines like to ensure all output */
  220. /* actually on the screen. */
  221.  
  222. flush_output(side) Side *side;  {  refresh();  }
  223.  
  224. /* General window clearing. */
  225.  
  226. clear_window(side, win)
  227. Side *side;
  228. int win;
  229. {
  230.     int i;
  231.  
  232.     if (wx[win] == 0 && wy[win] == 0 && ww[win] == COLS && wh[win] == LINES) {
  233.     clear();
  234.     } else {
  235.     for (i = 0; i < ww[win]; ++i) tmpbuf[i] = ' ';
  236.     tmpbuf[ww[win]] = '\0';
  237.     for (i = 0; i < wh[win]; ++i) mvaddstr(wy[win]+i, wx[win], tmpbuf);
  238.     }
  239. }
  240.  
  241. /* No world display for curses. */
  242.  
  243. draw_bar(side, x, y, len, color) Side *side; int x, y, len, color; {}
  244.  
  245. invert_box(side, vcx, vcy) Side *side; int vcx, vcy; {}
  246.  
  247. /* This interfaces higher-level drawing decisions to the rendition of */
  248. /* individual pieces of display.  Note that a display mode determines */
  249. /* whether one or two terrain characters get drawn. */
  250.  
  251. draw_terrain_row(side, x, y, buf, len, color)
  252. Side *side;
  253. int x, y, len, color;
  254. char *buf;
  255. {
  256.     int i, xi = x;
  257.  
  258.     for (i = 0; i < len; ++i) {
  259.     if (xi >= wx[side->map] + ww[side->map] - 2) break;
  260.     if (cur_at(side->map, xi, y)) {
  261.         addch(buf[i]);
  262.         addch((side->showmode == BORDERHEX ? ' ' : buf[i]));
  263.     }
  264.     xi += 2;
  265.     }
  266. }
  267.  
  268. /* Don't just position the cursor, but also clip and return the decision. */
  269.  
  270. cur_at(win, x, y)
  271. int win, x, y;
  272. {
  273.     if (x < 0 || x >= ww[win] || y < 0 || y >= wh[win]) {
  274.     return FALSE;
  275.     } else {
  276.     move(wy[win] + y, wx[win] + x);
  277.     return TRUE;
  278.     }
  279. }
  280.  
  281. /* Curses is never flashy... */
  282.  
  283. flash_position(side, x, y, tm) Side *side; int x, y, tm; {}
  284.  
  285. /* Curses cursor drawing is quite easy! (but ineffective? - see input fns) */
  286.  
  287. draw_cursor_icon(side, x, y)
  288. Side *side;
  289. int x, y;
  290. {
  291.     cur_at(side->map, x, y);
  292.     refresh();
  293. }
  294.  
  295. /* Doesn't seem to be necessary. */
  296.  
  297. draw_hex_icon(side, win, x, y, color, ch)
  298. Side *side;
  299. int win, x, y, color;
  300. char ch;
  301. {
  302. }
  303.  
  304. /* Splash a unit character onto some window. */
  305.  
  306. draw_unit_icon(side, win, x, y, u, color)
  307. Side *side;
  308. int win;
  309. int x, y, u, color;
  310. {
  311.     if (cur_at(win, x, y)) {
  312.     addch(utypes[u].uchar);
  313.     addch(' ');   /* inefficient, sigh */
  314.     }
  315. }
  316.  
  317. /* Use the second position in a "hex" for identification of enemies. */
  318.  
  319. draw_side_number(side, win, x, y, n, color)
  320. Side *side;
  321. int win, x, y, n, color;
  322. {
  323.     if (cur_at(win, x+1, y)) addch((n == -1) ? '`' : n + '0');
  324. }
  325.  
  326. /* Curses has enough trouble splatting stuff on the screen without doing */
  327. /* little flashes too... */
  328.  
  329. draw_blast_icon(side, win, x, y, type, color)
  330. Side *side;
  331. int win, x, y, type, color;
  332. {
  333. }
  334.  
  335. /* Unfortunately, terminals usually can't flash their screens. */
  336.  
  337. invert_whole_map(side) Side *side; {}
  338.  
  339. /* Mushroom clouds don't come out real well either. */
  340. /* This could be a little more elaborate. */
  341.  
  342. draw_mushroom(side, x, y, i)
  343. Side *side;
  344. int x, y, i;
  345. {
  346.     int sx, sy;
  347.  
  348.     xform(side, unwrap(side, x), y, &sx, &sy);
  349.     if (cur_at(side->map, sx, sy)) {
  350.     addstr("##");
  351.     flush_output(side);
  352.     if (i > 0) {
  353.         if (cur_at(side->map, sx-1, sy+1)) addstr("####");
  354.         if (cur_at(side->map, sx-2, sy)) addstr("######");
  355.         if (cur_at(side->map, sx-1, sy-1)) addstr("####");
  356.         flush_output(side);
  357.     }
  358.     }
  359. }
  360.  
  361. /* Indicate that bar graphs are out of the question. */
  362.  
  363. bar_graphs(side) Side *side;  {  return FALSE;  }
  364.  
  365. /* Thus this routine can be empty. */
  366.  
  367. draw_graph(side, number, amount, total, title)
  368. Side *side;
  369. int number, amount, total;
  370. {
  371. }
  372.  
  373. /* Drawing text is easy, as long as we can ignore the color of it. */
  374. /* Need to do manual clipping though. */
  375.  
  376. draw_text(side, win, x, y, str, color)
  377. Side *side;
  378. int win;
  379. int x, y, color;
  380. char *str;
  381. {
  382.     int i;
  383.  
  384.     if (cur_at(win, x, y)) {
  385.     for (i = 0; i < strlen(str); ++i) {
  386.         if (x + i >= ww[win]) return;
  387.         addch(str[i]);
  388.     }
  389.     }
  390. }
  391.  
  392. /* Can't draw lines, but this will substitute, sort of. */
  393.  
  394. draw_scratchout(side, pos)
  395. Side *side;
  396. int pos;
  397. {
  398.     int i;
  399.  
  400.     for (i = 0; i < 20; i += 2) {
  401.     if (cur_at(side->sides, i, pos)) addch('-');
  402.     }
  403. }
  404.  
  405. /* Beep the beeper! */
  406.  
  407. beep(side)
  408. Side *side;
  409. {
  410.     putchar('\007');
  411. }
  412.  
  413. /* Most help info is printable also. */
  414.  
  415. reveal_help(side)
  416. Side *side;
  417. {
  418.     notify(side, "Screen too small - writing into files instead.");
  419.     do_printables(side, 0);
  420.     return FALSE;
  421. }
  422.  
  423. conceal_help(side) Side *side; {}
  424.  
  425. /* Shut a single display down - presumably only called once. */
  426.  
  427. close_display(side)
  428. Side *side;
  429. {
  430.     clear();
  431.     refresh();
  432.     endwin();
  433.     side->display = 0;
  434. }
  435.  
  436. /* Completely redo a screen, making no assumptions about appearance. */
  437. /* This one is used frequently, especially when a window is exposed. */
  438.  
  439. redraw(side)
  440. Side *side;
  441. {
  442.     if (active_display(side)) {
  443.     erase_cursor(side);
  444.     clear_window(side, side->main);
  445.     show_note(side);
  446.     show_info(side);
  447.     show_prompt(side);
  448.     show_all_sides(side);
  449.     show_timemode(side);
  450.     show_clock(side);
  451.     show_state(side);
  452.     show_map(side);
  453.     show_world(side);
  454.     flush_output(side);
  455.     flush_input(side);
  456.     }
  457. }
  458.  
  459.